package com.think.cloud.thinkshop.mall.service.product.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.think.cloud.thinkshop.common.constant.product.ProductConstants;
import com.think.cloud.thinkshop.mall.controller.admin.product.vo.*;
import com.think.cloud.thinkshop.mall.controller.admin.productgroup.vo.ProductGroupRespVO;
import com.think.cloud.thinkshop.mall.convert.product.ProductAttrValueConvert;
import com.think.cloud.thinkshop.mall.convert.product.ProductConvert;
import com.think.cloud.thinkshop.mall.domain.*;
import com.think.cloud.thinkshop.mall.enums.common.CommonWhetherEnum;
import com.think.cloud.thinkshop.mall.enums.group.IntelligentGroupConditionEnum;
import com.think.cloud.thinkshop.mall.enums.group.IntelligentGroupScreenEnum;
import com.think.cloud.thinkshop.mall.enums.group.IntelligentGroupTypeEnum;
import com.think.cloud.thinkshop.mall.enums.product.ProductSkuTypeEnum;
import com.think.cloud.thinkshop.mall.mapper.*;
import com.think.cloud.thinkshop.mall.service.product.IProductAttrService;
import com.think.cloud.thinkshop.mall.service.product.IProductAttrValueService;
import com.think.cloud.thinkshop.mall.service.product.IProductService;
import com.think.cloud.thinkshop.mall.service.product.dto.DetailDTO;
import com.think.cloud.thinkshop.mall.service.product.dto.ProductResultDTO;
import com.think.cloud.thinkshop.mall.service.shippingtemplates.IShippingTemplatesProductRefService;
import com.think.cloud.thinkshop.mall.utils.RedisUtils;
import com.think.cloud.thinkshop.system.api.RemoteFileService;
import com.think.common.core.exception.enums.ErrorCode;
import com.think.common.core.exception.util.ServiceExceptionUtil;
import com.think.common.core.utils.PageUtils;
import com.think.common.core.utils.poi.ExcelUtil;
import com.think.common.core.web.page.TableDataInfo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static com.think.common.core.exception.enums.ErrorCode.PARAMETER_ERROR;

/**
 * 商品Service业务层处理
 *
 * @author zkthink
 * @date 2024-05-09
 */
@Slf4j
@Service
public class ProductServiceImpl implements IProductService {

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private IProductAttrService productAttrService;

    @Autowired
    private IProductAttrValueService productAttrValueService;

    @Autowired
    private ProductAttrValueMapper productAttrValueMapper;

    @Autowired
    private ProductGroupRelationMapper productGroupRelationMapper;

    @Autowired
    private ProductCategoryMapper productCategoryMapper;

    @Autowired
    private ProductGroupMapper productGroupMapper;

    @Autowired
    @Lazy
    private IShippingTemplatesProductRefService shippingTemplatesProductRefService;

    @Autowired
    private RemoteFileService remoteFileService;


    /**
     * 查询商品
     *
     * @param productId 商品主键
     * @return 商品
     */
    @Override
    public ProductDetailRespVO selectProductByProductId(Long productId) {
        Product product = findProductById(productId);
        ProductDetailRespVO  productDetail = ProductConvert.INSTANCE.convert(product);

        List<ProductAttr> productAttrs = getAttrList(productId);
        List<ProductAttrRespVO> productAttrRespVOS = buildProductAttrRespVO(productAttrs);
        productDetail.setAttrs(productAttrRespVOS);
        productDetail.setSkus(this.getSkus(productId, productDetail.getAttrs()));
        productDetail.setGroups(this.getProductGroupsByProductId(productId));
        Long categoryId = productDetail.getCategoryId();
        if (ObjectUtil.isNotNull(categoryId)) {
            ProductCategory category = this.getProductCategory(categoryId);
            productDetail.setCategoryName(ObjectUtil.isNotNull(category) ? category.getName() : null);
        }
        return productDetail;
    }

    //获取产品分组
    private List<ProductGroupRespVO> getProductGroupsByProductId(Long productId) {
        return productGroupMapper.selectListByProductId(productId);
    }

    //获取产品分类
    private ProductCategory getProductCategory(Long categoryId) {
        return productCategoryMapper.selectById(categoryId);
    }

    //获取产品sku
    private List<ProductSkuRespVO> getSkus(Long productId, List<ProductAttrRespVO> attrs) {
        List<ProductSkuRespVO> list = ProductAttrValueConvert.INSTANCE.convertList1(productAttrValueService
                .selectProductAttrValueList(ProductAttrValue.builder().productId(productId).build()));
        for (ProductSkuRespVO productSkuResp : list) {
            Map<String, String> skuDetail = new HashMap<>();
            String[] sku = productSkuResp.getSku().split(",");
            for (int i = 0; i < sku.length; i++) {
                skuDetail.put(attrs.get(i).getValue(), sku[i]);
            }
            productSkuResp.setSkuDetail(skuDetail);
        }
        return list;
    }

    @Override
    public Product findProductById(Long productId) {
        return productMapper.selectById(productId);
    }

    @Override
    public Product findHistoryProductById(Long productId) {
        return productMapper.findHistoryProductById(productId);
    }

    @Override
    public List<Product> selectProductByProductIds(List<Long> productIds) {
        return productMapper.selectBatchIds(productIds);
    }

    /**
     * 查询商品列表
     *
     * @param vo 商品
     * @return 商品
     */
    @Override
    public TableDataInfo selectProductList(ProductPageReqVO vo) {
        List<Product> products = productMapper.selectList(vo);
        List<ProductPageRespVO> vos = ProductConvert.INSTANCE.convertList(products);
        // 设置价格范围
        if (CollectionUtil.isNotEmpty(vos)) {
            vos.forEach(res -> {
                res.setPriceRange(res.getMaxPrice().compareTo(res.getMinPrice()) == 0 ?
                        res.getMinPrice().toString() : res.getMinPrice() + "~" + res.getMaxPrice());
                res.setImage(getImage(res.getImage()));
            });
        }
        return new TableDataInfo(vos, PageUtils.getTotal(products));
    }

    /**
     * 获取商品第一张图片
     */
    private String getImage(String images) {
        return images.split(",")[0];
    }

    /**
     * 新增商品
     *
     * @param vo 参数
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertProduct(SaveProductReqVO vo) {
        Product product = ProductConvert.INSTANCE.convert(vo);
        this.productInfoSave(product, vo.getSkus(), vo.getAttrs(), vo.getGroupIds(), false);
    }

    /**
     * 修改商品
     *
     * @param vo 参数
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProduct(UpdateProductReqVO vo) {
        Product product = ProductConvert.INSTANCE.convert(vo);
        this.productInfoSave(product, vo.getSkus(), vo.getAttrs(), vo.getGroupIds(), true);
    }

    //新增或修改商品
    private void productInfoSave(Product product, List<ProductSkuReqVO> skusParam, List<ProductAttrReqVO> attrsParam,
                             List<Long> groupIds, boolean isUpdate) {
        Integer skuType = product.getSkuType();
        List<ProductSkuReqVO> skus = this.setSingleSku(skuType, skusParam);
        List<ProductAttrReqVO> attrs = this.setSingleAttrs(skuType, attrsParam);
        ProductResultDTO productResultDTO = getProductResult(skus);
        // 设置最小价格
        product.setMinPrice(productResultDTO.getMinPrice());
        // 设置最大价格
        product.setMaxPrice(productResultDTO.getMaxPrice());
        // 设置库存
        product.setStock(productResultDTO.getStock());
        Long productId;
        if (isUpdate) {
            productMapper.updateById(product);
            productId = product.getProductId();
            // 更新商品，需要删除原有的关系数据
            // 删除旧属性
            productAttrService.deleteByProductId(productId);
            // 删除旧规格信息
            productAttrValueService.deleteByProductId(productId);
            // 删除分组关联信息
            productGroupRelationMapper.delete(new LambdaQueryWrapper<ProductGroupRelation>()
                    .eq(ProductGroupRelation::getProductId, product.getProductId()));
        } else {
            // 新增商品，需要生成商品编号
            String productCode = RedisUtils.getSerialNumber(
                    ProductConstants.PRODUCT_CODE_PREFIX, ProductConstants.PRODUCT_CODE_REDIS_KEY,
                    ProductConstants.DATE_FORMAT, ProductConstants.NUMBER_FORMAT
            );
            product.setProductCode(productCode);
            productMapper.insert(product);
            productId = product.getProductId();
        }
        List<ProductAttr> productAttrs = attrConvert(attrs, productId);
        // 保存属性
        productAttrService.batchInsertProductAttr(productAttrs);
        List<ProductAttrValue> productAttrValues = attrValueConvert(skus, productId, productAttrs);
        // 保存规格信息
        productAttrValueService.batchInsertProductAttrValue(productAttrValues);
        // 保存分组关联信息
        if (CollectionUtil.isNotEmpty(groupIds)) {
            this.saveGroupRelations(groupIds, productId);
        }
    }

    //保存分组关系
    private void saveGroupRelations(List<Long> groupIds, Long productId) {
        List<ProductGroupRelation> groupRelations =
                groupIds.stream().map(res -> ProductGroupRelation.builder()
                        .groupId(res).productId(productId).build()).collect(Collectors.toList());
        productGroupRelationMapper.batchInsert(groupRelations);
    }

    //检查是否设置单规格的attrs
    private List<ProductAttrReqVO> setSingleAttrs(Integer skuType, List<ProductAttrReqVO> attrs) {
        if (skuType.equals(ProductSkuTypeEnum.SINGLE.getValue())) {
            ProductAttrReqVO productAttrReqVO = attrs.get(0);
            productAttrReqVO.setValue("单规格");
            productAttrReqVO.setDetail(Collections.singletonList("默认"));
            attrs.set(0, productAttrReqVO);
            return attrs;
        }
        return attrs;
    }

    //检查是否设置单规格的sku
    private List<ProductSkuReqVO> setSingleSku(Integer skuType, List<ProductSkuReqVO> skus) {
        if (skuType.equals(ProductSkuTypeEnum.SINGLE.getValue())) {
            ProductSkuReqVO productSkuReqVO = skus.get(0);
            HashMap<String, String> map = new HashMap<>();
            map.put("单规格", "默认");
            productSkuReqVO.setDetail(map);
            skus.set(0, productSkuReqVO);
            return skus;
        }
        return skus;
    }

    private List<ProductAttr> attrConvert(List<ProductAttrReqVO> attrs, Long productId) {
        return attrs.stream()
                .map(res -> ProductAttr.builder().productId(productId).attrName(res.getValue())
                        .attrValues(String.join(",", res.getDetail())).build()).collect(Collectors.toList());
    }

    private List<ProductAttrValue> attrValueConvert(List<ProductSkuReqVO> skus, Long productId, List<ProductAttr> productAttrs) {
        skus.forEach(res -> res.setSku(getSku(res, productAttrs)));
        List<ProductAttrValue> productAttrValues =
                ProductAttrValueConvert.INSTANCE.convertList(skus);
        productAttrValues.forEach(res -> res.setProductId(productId));
        return productAttrValues;
    }

    private String getSku(ProductSkuReqVO sku, List<ProductAttr> productAttrs) {
        List<String> skuList = new ArrayList<>();
        productAttrs.forEach(res -> skuList.add(sku.getDetail().get(res.getAttrName())));
        return String.join(",", skuList);
    }

    /**
     * 计算商品信息
     *
     * @param skus
     * @return
     */
    private ProductResultDTO getProductResult(List<ProductSkuReqVO> skus) {
        ProductResultDTO dto = new ProductResultDTO();
        // 计算最小价格
        dto.setMinPrice(skus.stream().map(ProductSkuReqVO::getPrice)
                .min(Comparator.naturalOrder()).orElse(BigDecimal.ZERO));
        // 计算最大价格
        dto.setMaxPrice(skus.stream().map(ProductSkuReqVO::getPrice)
                .max(Comparator.naturalOrder()).orElse(BigDecimal.ZERO));
        // 计算库存
        dto.setStock(skus.stream().map(ProductSkuReqVO::getStock)
                .reduce(Integer::sum).orElse(0));
        return dto;
    }

    /**
     * 批量删除商品信息
     *
     * @param productIds 主键集合
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(List<Long> productIds) {
        // 判断是否存在未删除订单
        int res = productMapper.deleteBatchIds(productIds);
        if (res > 0) {
            shippingTemplatesProductRefService.deleteByProductIds(productIds);
        }
    }

    @Override
    public void grounding(GroundingProductReqVO vo) {
        Product product = this.findProductById(vo.getProductId());
        if (CommonWhetherEnum.YES.getValue().equals(vo.getType()) && product.getStock() == 0) {
            throw ServiceExceptionUtil.exception(ErrorCode.STOCK_IS_ZERO_ERROR);
        } else {
            product.setIsShow(vo.getType());
            productMapper.updateById(product);
        }

    }

    @Override
    public List<Long> intelligentSearch(IntelligentSearchProductReqVO vo) {
        return productMapper.intelligentSearch(generateFilterSql(vo));
    }

    /**
     * 生成过滤条件的SQL字符串
     *
     * @param vo
     * @return
     */
    private String generateFilterSql(IntelligentSearchProductReqVO vo) {
        StringBuilder sql = new StringBuilder();
        sql.append("(");
        for (IntelligentSearchFilterReqVO filter : vo.getFilters()) {
            sql.append(IntelligentGroupTypeEnum.toType(filter.getType()).getValue() + " ")
                    .append(IntelligentGroupConditionEnum.toType(filter.getCondition()).getValue())
                    .append(" " + filter.getValue())
                    .append(" " + IntelligentGroupScreenEnum.toType(vo.getScreen()).getValue() + " ");
        }
        // 删除最后一个连接字
        sql.delete(sql.length() - 4, sql.length());
        sql.append(")");
        return sql.toString();
    }

    /**
     * 获取生成的属性
     *
     * @param id      商品id
     * @param jsonStr jsonStr
     * @return map
     */
    @Override
    public Map<String, Object> getFormatAttr(Long id, String jsonStr) {
        JSONObject jsonObject = JSON.parseObject(jsonStr);
        Map<String, Object> resultMap = new LinkedHashMap<>(3);

        if (jsonObject == null || jsonObject.get("attrs") == null || jsonObject.getJSONArray("attrs").isEmpty()) {
            resultMap.put("attr", new ArrayList<>());
            resultMap.put("value", new ArrayList<>());
            resultMap.put("header", new ArrayList<>());
            return resultMap;
        }

        List<ProductFormatAttrReqVO> formatDetailDTOList = JSON.parseArray(jsonObject.get("attrs").toString(),
                ProductFormatAttrReqVO.class);
        //formatDetailDTOList
        DetailDTO detailDto = this.attrFormat(formatDetailDTOList);

        List<Map<String, Object>> headerMapList = null;
        List<Map<String, Object>> valueMapList = new ArrayList<>();
        String align = "center";
        Map<String, Object> headerMap = new LinkedHashMap<>();
        for (Map<String, Map<String, String>> map : detailDto.getRes()) {
            Map<String, String> detail = map.get("detail");
            String[] detailArr = detail.values().toArray(new String[]{});

            String sku = String.join(",", detailArr);

            Map<String, Object> valueMap = new LinkedHashMap<>();

            List<String> detailKeys = new ArrayList<>(detail.keySet());

            int i = 0;
            headerMapList = new ArrayList<>();
            for (String title : detailKeys) {
                headerMap.put("title", title);
                headerMap.put("minWidth", "130");
                headerMap.put("align", align);
                headerMap.put("key", "value" + (i + 1));
                headerMap.put("slot", "value" + (i + 1));
                headerMapList.add(ObjectUtil.clone(headerMap));
                i++;
            }

            String[] detailValues = detail.values().toArray(new String[]{});
            for (int j = 0; j < detailValues.length; j++) {
                String key = "value" + (j + 1);
                valueMap.put(key, detailValues[j]);
            }
            valueMap.put("detail", detail);
            valueMap.put("sku", "");
            valueMap.put("image", "");
            valueMap.put("price", 0);
            valueMap.put("originalPrice", 0);
            valueMap.put("stock", 0);
            valueMap.put("weight", 0);
            if (id > 0) {
                ProductAttrValue productAttrValue = productAttrValueMapper.selectOne(
                        (Wrappers.<ProductAttrValue>lambdaQuery()
                                .eq(ProductAttrValue::getProductId, id)
                                .eq(ProductAttrValue::getSku, sku)));
                if (productAttrValue != null) {
                    valueMap.put("sku", productAttrValue.getSku());
                    valueMap.put("image", productAttrValue.getImage());
                    valueMap.put("price", productAttrValue.getPrice());
                    valueMap.put("originalPrice", productAttrValue.getOriginalPrice());
                    valueMap.put("stock", productAttrValue.getStock());
                    valueMap.put("weight", productAttrValue.getWeight());
                }
            }

            valueMapList.add(ObjectUtil.clone(valueMap));

        }

        assert headerMapList != null;
        this.addMap(headerMap, headerMapList, align);


        resultMap.put("attr", formatDetailDTOList);
        resultMap.put("value", valueMapList);
        resultMap.put("header", headerMapList);

        return resultMap;
    }

    /**
     * 组合规则属性算法
     *
     * @param formatDetailDTOList 组合规则算法对象
     * @return DetailDto
     */
    private DetailDTO attrFormat(List<ProductFormatAttrReqVO> formatDetailDTOList) {

        List<String> data = new ArrayList<>();
        List<Map<String, Map<String, String>>> res = new ArrayList<>();

        formatDetailDTOList.stream()
                .map(ProductFormatAttrReqVO::getDetail)
                .forEach(i -> {
                    if (i == null || i.isEmpty()) {
                        throw ServiceExceptionUtil.exception(PARAMETER_ERROR);
                    }
                    String str = ArrayUtil.join(i.toArray(), ",");
                    if (str.contains("-")) {
                        throw ServiceExceptionUtil.exception(PARAMETER_ERROR);
                    }
                });

        if (formatDetailDTOList.size() > 1) {
            for (int i = 0; i < formatDetailDTOList.size() - 1; i++) {
                if (i == 0) {
                    data = formatDetailDTOList.get(i).getDetail();
                }
                List<String> tmp = new LinkedList<>();
                for (String valueStr : data) {
                    for (String g : formatDetailDTOList.get(i + 1).getDetail()) {
                        String rep2 = "";
                        if (i == 0) {
                            rep2 = formatDetailDTOList.get(i).getValue() + "_" + valueStr + "-"
                                    + formatDetailDTOList.get(i + 1).getValue() + "_" + g;
                        } else {
                            rep2 = valueStr + "-"
                                    + formatDetailDTOList.get(i + 1).getValue() + "_" + g;
                        }

                        tmp.add(rep2);

                        if (i == formatDetailDTOList.size() - 2) {
                            Map<String, Map<String, String>> repMap = getMap(rep2);
                            res.add(repMap);
                        }
                    }

                }

                if (!tmp.isEmpty()) {
                    data = tmp;
                }
            }
        } else {
            List<String> dataArr = new ArrayList<>();
            for (ProductFormatAttrReqVO formatDetailDTO : formatDetailDTOList) {
                for (String str : formatDetailDTO.getDetail()) {
                    Map<String, Map<String, String>> detailMap = new LinkedHashMap<>();
                    dataArr.add(formatDetailDTO.getValue() + "_" + str);
                    Map<String, String> map1 = new LinkedHashMap<>();
                    map1.put(formatDetailDTO.getValue(), str);
                    detailMap.put("detail", map1);
                    res.add(detailMap);
                }
            }
            String s = StrUtil.join("-", dataArr);
            data.add(s);
        }

        DetailDTO detailDto = new DetailDTO();
        detailDto.setData(data);
        detailDto.setRes(res);

        return detailDto;
    }

    private static Map<String, Map<String, String>> getMap(String rep2) {
        Map<String, Map<String, String>> repMap = new LinkedHashMap<>();
        Map<String, String> repTempMap = new LinkedHashMap<>();
        for (String h : rep2.split("-")) {
            List<String> splitList = Arrays.asList(h.split("_"));
            if (splitList.size() > 1) {
                StringBuilder tempStr = new StringBuilder();
                //前面用_分割导致名称中带多个_被去掉，所以重组的时候需要拼上
                for (int j = 1; j < splitList.size(); j++) {
                    if (j == splitList.size() - 1) {
                        tempStr.append(splitList.get(j));
                    } else {
                        tempStr.append(splitList.get(j)).append("_");
                    }
                }
                repTempMap.put(splitList.get(0), tempStr.toString());
            } else {
                repTempMap.put(splitList.get(0), "");
            }
        }
        repMap.put("detail", repTempMap);
        return repMap;
    }

    /**
     * 增加表头
     *
     * @param headerMap     headerMap
     * @param headerMapList headerMapList
     * @param align         align
     */
    private void addMap(Map<String, Object> headerMap, List<Map<String, Object>> headerMapList, String align) {
        headerMap.put("title", "图片");
        headerMap.put("slot", "image");
        headerMap.put("align", align);
        headerMap.put("minWidth", 80);
        headerMapList.add(ObjectUtil.clone(headerMap));

        headerMap.put("title", "售价");
        headerMap.put("slot", "price");
        headerMap.put("align", align);
        headerMap.put("minWidth", 120);
        headerMapList.add(ObjectUtil.clone(headerMap));

        headerMap.put("title", "原价");
        headerMap.put("slot", "originalPrice");
        headerMap.put("align", align);
        headerMap.put("minWidth", 140);
        headerMapList.add(ObjectUtil.clone(headerMap));

        headerMap.put("title", "库存");
        headerMap.put("slot", "stock");
        headerMap.put("align", align);
        headerMap.put("minWidth", 140);
        headerMapList.add(ObjectUtil.clone(headerMap));

        headerMap.put("title", "重量(KG)");
        headerMap.put("slot", "weight");
        headerMap.put("align", align);
        headerMap.put("minWidth", 140);
        headerMapList.add(ObjectUtil.clone(headerMap));

        headerMap.put("title", "操作");
        headerMap.put("slot", "action");
        headerMap.put("align", align);
        headerMap.put("minWidth", 70);
        headerMapList.add(ObjectUtil.clone(headerMap));
    }


    @Override
    public void getImportTemplate(HttpServletResponse response) {
        ExcelUtil<SaveProductExcelTemplateVO> util = new ExcelUtil<>(SaveProductExcelTemplateVO.class);

        List<SaveProductExcelTemplateVO> template = new ArrayList<>();

        SaveProductExcelTemplateVO product = buildRow(
                "商品A", "在此填写商品简介", "在此描述商品详情", 2,
                "颜色:红,黄,蓝|尺寸:大,中,小",
                "颜色:黄|尺寸:小=原价:100|售价:99|库存:10|重量:1\n" +
                        "颜色:红|尺寸:大=原价:99|售价:98|库存:13|重量:1",
                "类目A", "分组A|分组B", 1, 1
        );
        SaveProductExcelTemplateVO product2 = buildRow(
                "商品C", "在此填写商品简介", "在此描述商品详情", 1,
                "单规格:默认",
                "单规格:默认=原价:99|售价:97|库存:10|重量:1",
                "类目A", "分组A|分组B", 1, 1
        );
        template.addAll(Arrays.asList(product, product2));
        util.exportExcel(response, template, "商品导入模版");
    }

    private SaveProductExcelTemplateVO buildRow(String name, String introduce, String detail, Integer skuType,
                                                String attr, String value, String category, String groups,
                                                Integer tax, Integer show) {
        SaveProductExcelTemplateVO row = new SaveProductExcelTemplateVO();
        row.setProductName(name);
        row.setIntroduce(introduce);
        row.setDetail(detail);
        row.setSkuType(skuType);
        row.setAttr(attr);
        row.setValue(value);
        row.setCategory(category);
        row.setGroups(groups);
        row.setTax(tax);
        row.setIsShow(show);
        return row;
    }

    @Override
    public ImportProductResultVO importProductByExcel(MultipartFile file) throws IOException {

        String folder = "./import_product";
        String importProduct = folder + "/import_product.xlsx";
        saveFile(file.getInputStream(), importProduct);

        ExcelUtil<SaveProductExcelTemplateVO> util = new ExcelUtil<>(SaveProductExcelTemplateVO.class);
        List<SaveProductExcelTemplateVO> list = util.importExcel(file.getInputStream());
        list = list.stream().peek(new Consumer<SaveProductExcelTemplateVO>() {
            @SneakyThrows
            @Override
            public void accept(SaveProductExcelTemplateVO item) {
                String image = item.getImage();
                if (!"".equals(image)) {
                    MultipartFile multipartFile = convertFileToMultipartFile(FileUtils.getFile(image));
                    String url = remoteFileService.upload(multipartFile).getData().getUrl();
                    item.setImage(url);
                }
            }
        }).collect(Collectors.toList());
        FileUtils.deleteDirectory(FileUtils.getFile(folder));
        return buildParam2SaveProduct(list);
    }

    /**
     * 将File类型转换为MultipartFile类型的文件，便于上传
     */
    public static MultipartFile convertFileToMultipartFile(File file) throws IOException {
        byte[] fileBytes = FileUtils.readFileToByteArray(file);
        return new MockMultipartFile(file.getName(), file.getName(),
                null, fileBytes);
    }

    private File saveFile(InputStream inputStream, String fileName) throws IOException {
        OutputStream outputStream = null;
        try {
            File outputFile = new File(fileName);
            if (!outputFile.getParentFile().exists()) {
                outputFile.getParentFile().mkdirs();
            }
            outputStream = Files.newOutputStream(outputFile.toPath());
            byte[] buffer = new byte[1024];
            int length;

            while ((length = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, length);
            }
            return outputFile;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return null;
    }

    public ImportProductResultVO buildParam2SaveProduct(List<SaveProductExcelTemplateVO> list) {
        List<String> failedSet = new ArrayList<>();
        int failed = 0;

        List<SaveProductReqVO> paramSet = new ArrayList<>();
        for (SaveProductExcelTemplateVO product : list) {
            String productName = null;
            try {
                SaveProductReqVO param = ProductConvert.INSTANCE.convert4(product);
                productName = product.getProductName();
                param.setCategoryId(this.findCategoryIdByName(product.getCategory()));
                param.setGroupIds(this.findGroupIdByName(Arrays.asList(product.getGroups().split("\\|"))));
                //规格类型
                Integer skuType = product.getSkuType();
                //提取当前产品的attr
                List<ProductAttrReqVO> attrsList = new ArrayList<>();
                if (skuType == 1) {
                    attrsList.add(new ProductAttrReqVO("单规格", Collections.singletonList("默认")));
                } else {
                    String attrs = product.getAttr();
                    String[] attrSet = attrs.split("\\|"); // 分离每种属性
                    for (String attr : attrSet) {
                        String[] split = attr.split(":");
                        String attrName = split[0];
                        List<String> attrDetails = Arrays.asList(split[1].split(","));
                        ProductAttrReqVO productAttrReqVO = new ProductAttrReqVO(attrName, attrDetails);
                        attrsList.add(productAttrReqVO);
                    }
                }
                param.setAttrs(attrsList);
                //构建sku参数
                List<ProductSkuReqVO> skuParamList = new ArrayList<>();

                for (String line : product.getValue().split("\n")) {
                    Map<String, String> detailMap = new HashMap<>();
                    String[] split = line.split("=");
                    String attr = split[0];//详情属性
                    String sku = split[1]; //具体规格值 ，库存等

                    for (String s : attr.split("\\|")) {
                        String[] split1 = s.split(":");
                        String attrName = split1[0];
                        String attrValue = split1[1];
                        boolean judg1 = attrsList.stream().anyMatch(productAttrReqVO -> productAttrReqVO.getValue().equals(attrName));
                        boolean judg2 = attrsList.stream().anyMatch(productAttrReqVO -> productAttrReqVO.getDetail().contains(attrValue));
                        if (!judg1 || !judg2) {
                        }
                        detailMap.put(attrName, attrValue);
                    }
                    String[] params = sku.split("\\|");
                    ProductSkuReqVO build = ProductSkuReqVO.builder()
                            .sku("")
                            .detail(detailMap)
                            .image(product.getImage())
                            .originalPrice(new BigDecimal(params[0].split(":")[1]))
                            .price(new BigDecimal(params[1].split(":")[1]))
                            .stock(Integer.parseInt(params[2].split(":")[1]))
                            .weight(new BigDecimal(params[3].split(":")[1]))
//                            .volume(new BigDecimal(split[4].split(":")[1]))
                            .build();
                    skuParamList.add(build);
                }
                param.setSkus(skuParamList);
                paramSet.add(param);
            } catch (Exception ex) {
                failed++;
                failedSet.add(productName);
            }
        }
        for (SaveProductReqVO saveProductReqVO : paramSet) {
            insertProduct(saveProductReqVO);
        }
        return new ImportProductResultVO(list.size() - failed, failed, failedSet);
    }

    private Long findCategoryIdByName(String name) {
        return productCategoryMapper.selectOne(
                Wrappers.<ProductCategory>lambdaQuery()
                        .eq(ProductCategory::getName, name)
        ).getCategoryId();
    }

    public List<Long> findGroupIdByName(List<String> names) {
        List<ProductGroup> productGroups = productGroupMapper.selectList(
                Wrappers.<ProductGroup>lambdaQuery().in(ProductGroup::getName, names)
        );
        return productGroups.stream().map(ProductGroup::getGroupId).collect(Collectors.toList());
    }

    @Override
    public void exportProduct(HttpServletResponse response) {
        List<Product> products = productMapper.selectList(Wrappers.<Product>lambdaQuery()
//                .eq()
        );
        List<SaveProductExcelTemplateVO> list = ProductConvert.INSTANCE.convertList2(products);
        list = list.stream().peek(item -> {
            item.setImage(item.getImage().replace(",", "\n"));
            if (ObjectUtil.isNotNull(item.getCategoryId())) {
                ProductCategory category = this.getProductCategory(item.getCategoryId());
                item.setCategory(ObjectUtil.isNotNull(category) ? category.getName() : null);
            }
            String groups = this.getProductGroupsByProductId(item.getProductId()).stream()
                    .map(ProductGroupRespVO::getName).collect(Collectors.joining("|"));
            item.setGroups(groups);
            List<ProductAttr> attrList = getAttrList(item.getProductId());
            item.setAttr(getAttrStr(attrList));
            item.setValue(getSkuStr(this.getSkus(item.getProductId(), buildProductAttrRespVO(attrList))));
        }).collect(Collectors.toList());
        ExcelUtil<SaveProductExcelTemplateVO> util = new ExcelUtil<>(SaveProductExcelTemplateVO.class);
        util.exportExcel(response, list, "导出商品");
    }

    private String getSkuStr(List<ProductSkuRespVO> skus) {
        StringBuilder stringBuilder = new StringBuilder();
        for (ProductSkuRespVO productSkuRespVO : skus) {
            Map<String, String> skuDetail = productSkuRespVO.getSkuDetail();
            int i = 0;
            int size = skuDetail.size();
            for (String attr : skuDetail.keySet()) {
                String attrValue = skuDetail.get(attr);
                stringBuilder.append(attr).append(":").append(attrValue).append(i < size - 1 ? "|" : "=");
                i++;
            }
            BigDecimal originalPrice = productSkuRespVO.getOriginalPrice();
            stringBuilder.append("原价:").append(originalPrice).append("|");
            BigDecimal price = productSkuRespVO.getPrice();
            stringBuilder.append("售价:").append(price).append("|");
            Integer stock = productSkuRespVO.getStock();
            stringBuilder.append("库存:").append(stock).append("|");
            BigDecimal weight = productSkuRespVO.getWeight();
            stringBuilder.append("重量:").append(weight == null ? "0" : weight).append("\n");
//            BigDecimal volume = productSkuRespVO.getVolume();
//            stringBuilder.append("体积:").append(volume == null ? "0" : volume).append("\n");
        }
        return stringBuilder.toString();

    }

    private List<ProductAttr> getAttrList(Long productId) {
        return productAttrService.selectProductAttrList(
                ProductAttr.builder().productId(productId).build()
        );
    }

    private List<ProductAttrRespVO> buildProductAttrRespVO(List<ProductAttr> productAttrs) {
        return productAttrs.stream().map(res ->
                ProductAttrRespVO.builder().productId(res.getProductId())
                        .attrId(res.getAttrId()).value(res.getAttrName())
                        .detail(Arrays.asList(res.getAttrValues().split(","))).build()
        ).collect(Collectors.toList());
    }

    private String getAttrStr(List<ProductAttr> productAttrs) {
        return productAttrs.stream()
                .map(productAttr -> productAttr.getAttrName() + ":" + productAttr.getAttrValues())
                .collect(Collectors.joining("|"));
    }
}
